package com.spzx.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.security.config.ThreadPoolUtil;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.SkuStock;
import com.spzx.product.api.domain.query.ProductSkuQuery;
import com.spzx.product.api.domain.vo.ProductSkuVO;
import com.spzx.product.api.domain.vo.SkuPriceVO;
import com.spzx.product.api.domain.vo.SkuStockVO;
import com.spzx.product.api.domain.vo.SpecValueVO;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.service.ProductDetailsService;
import com.spzx.product.service.ProductService;
import com.spzx.product.service.ProductSkuService;
import com.spzx.product.service.SkuStockService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class ProductSkuServiceImpl extends ServiceImpl<ProductSkuMapper , ProductSku>
    implements ProductSkuService {
    @Lazy
    @Resource
    ProductService productService;
    @Resource
    SkuStockService skuStockService;
    @Resource
    ProductDetailsService productDetailsService;
    @Override
    public List<ProductSku> selectIndexSkus() {

        return baseMapper.selectIndexSkus();
    }

    @Override
    public Page<ProductSku> selectListSkus(ProductSkuQuery query) {
        //1、封装分页条件对象
        Page<ProductSku> page = new Page<>(query.getPageNo(),query.getPageSize());
        //=== 2、通过QueryWrapper组装条件: 多表联查时，queryWrapper不是特别方便使用

        //3、传入query条件对象
        List<ProductSku> list = baseMapper.selectListSkus(page,query);
        //4、将查询的数据集合设置给page对象
        page.setRecords(list);
        return page;
    }
    /*
        Callable+FutureTask : 可以创建异步任务
                        可以捕获异步任务的异常  + 阻塞获取异步任务的结果
        juc提供了异步编排： CompletableFuture
            可以将复杂的多个任务 组合成 串行或者并行的方式来执行 提高执行效率

         |- 1 根据skuid查询sku详情
            |-- 2 解析sku的价格封装为 skuPriceVO对象
            |-- 3 根据sku的productId查询spu
                |--- 4 根据spu的规格属性值解析得到 SpecValueList  & 以及轮播图 sliderUrlList
            |-- 6 根据productId查询 detailsImageUrlList 详情图列表
            |-- 7 根据productId查询它所有的sku集合
                |--- 8 将sku集合转为 specValue映射skuId的map集合
        |- 5 将sku集合转为 specValue映射skuId的map集合

     */
    @Override
    public ProductSkuVO selectSkuDetails(Long skuId) {
        ProductSkuVO skuVO = new ProductSkuVO();
        //1、根据id查询sku详情
        CompletableFuture<ProductSku> cf1 = CompletableFuture.supplyAsync(() -> {
            ProductSku productSku = this.getById(skuId);
            if (productSku == null) {
                throw new ServiceException("商品数据不存在");
            }
            skuVO.setProductSku(productSku);
            return productSku;
        }, ThreadPoolUtil.threadPoolExecutor());

        //2、解析sku的价格封装为 skuPriceVO对象
        cf1.whenComplete((sku,e)->{ //接收的参数是 cf1的异步编排任务返回的结果, 和前面可能出现的异常
            SkuPriceVO skuPriceVO = new SkuPriceVO();
            skuPriceVO.setSkuId(skuId);
            skuPriceVO.setSalePrice(sku.getSalePrice());
            skuPriceVO.setMarketPrice(sku.getMarketPrice());
            skuVO.setSkuPrice(skuPriceVO);
        });

        //3、根据sku的productId查询spu
        CompletableFuture<Void> cf3 = cf1.thenAcceptAsync((sku) -> {
            Long productId = sku.getProductId();
            Product product = productService.getById(productId);
            //4、根据spu的规格属性值解析得到 SpecValueList  & 以及轮播图 sliderUrlList
            //轮播图
            List<String> sliderUrlList = StringUtils.isEmpty(product.getSliderUrls()) ? null :
                    Arrays.asList(product
                            .getSliderUrls().split(","));
            //spu的规格参数值
            List<SpecValueVO> specValueVOS = JSON.parseArray(product.getSpecValue(), SpecValueVO.class);

            skuVO.setProduct(product);
            skuVO.setSliderUrlList(sliderUrlList);
            skuVO.setSpecValueList(specValueVOS);

        }, ThreadPoolUtil.threadPoolExecutor());


        //5、根据sku的id查询自己的库存  SkuStockVo
        CompletableFuture<Void> cf5 = CompletableFuture.runAsync(() -> {
            SkuStock skuStock = skuStockService.getOne(Wrappers.lambdaQuery(SkuStock.class)
                    .eq(SkuStock::getSkuId, skuId)
                    .last("limit 1"));
            SkuStockVO skuStockVO = new SkuStockVO();
            skuStockVO.setSkuId(skuId);
            skuStockVO.setAvailableNum(skuStock.getAvailableNum());
            skuStockVO.setSaleNum(skuStockVO.getSaleNum());
            skuVO.setSkuStockVo(skuStockVO);

        }, ThreadPoolUtil.threadPoolExecutor());

        //6、根据productId查询 detailsImageUrlList 详情图列表
        CompletableFuture<Void> cf6 =  cf1.thenAcceptAsync(sku->{
            ProductDetails productDetails = productDetailsService.getById(sku.getProductId());
            List<String> detailsImageUrlList  = productDetails!=null?
                    Arrays.asList(productDetails.getImageUrls().split(",")):null;
            skuVO.setDetailsImageUrlList(detailsImageUrlList);
        });

        //7、根据productId查询它所有的sku集合
        CompletableFuture<Void> cf7 = cf1.thenAcceptAsync(sku->{
            List<ProductSku> skus = this.list(Wrappers.lambdaQuery(ProductSku.class)
                    .eq(ProductSku::getProductId, sku.getProductId())
                    .eq(ProductSku::getStatus, 1));
            //8、将sku集合转为 specValue映射skuId的map集合
//            skus.stream().collect(Collectors.toMap(ProductSku::getSkuSpec, ProductSku::getId));
            Map<String,String> map = new HashMap<>();
            skus.forEach(item->{
                map.put(item.getSkuSpec() , item.getId().toString());
            });
            skuVO.setSkuSpecValueMap(map);
        });
        //9、将上面的数据组装为 ProductSkuVO对象
        //阻塞等待所有异步任务执行结束
        CompletableFuture.allOf(cf1,cf3,cf5,cf6,cf7).join();
        return skuVO;
    }

    @Override
    public Map<Long, BigDecimal> getSkusPrice(List<Long> skuIds) {
        if(CollectionUtils.isEmpty(skuIds)){
            throw new ServiceException("订单项不能为空");
        }
        List<ProductSku> productSkus = this.list(Wrappers.lambdaQuery(ProductSku.class)
                .select(ProductSku::getId, ProductSku::getSalePrice)
                .in(ProductSku::getId, skuIds)
        );
        return productSkus.stream().collect(Collectors.toMap(ProductSku::getId , ProductSku::getSalePrice));
    }

}
